Foundations of the Web
How Websites Work
When you visit a website, your browser sends a request to a server. The server responds with files — primarily HTML, CSS, and JavaScript. The browser then renders these files into the visual page you see.
- HTML — defines the structure and content (the skeleton)
- CSS — controls the visual style and layout (the skin)
- JavaScript — adds behavior and interactivity (the muscles)
Setting Up Your Environment
All you need to start is a text editor and a browser. Recommended tools:
- VS Code — free, powerful, with HTML/CSS IntelliSense
- Live Server extension — auto-refreshes your browser on save
- Browser DevTools — press
F12to inspect elements and debug styles
index.html — this is the default page browsers look for when visiting a website.
HTML Document Structure
The Boilerplate
Every HTML5 page starts with this standard structure. This is your blank canvas.
<!-- Tell the browser this is HTML5 --> <!DOCTYPE html> <html lang="en"> <head> <!-- Character encoding: supports all characters --> <meta charset="UTF-8" /> <!-- Makes the page responsive on mobile devices --> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <!-- Tab title and search engine title --> <title>My Website</title> <!-- Link your CSS file --> <link rel="stylesheet" href="style.css" /> </head> <body> <!-- All visible content goes here --> <h1>Hello, World!</h1> <!-- Link your JavaScript file (at the end of body) --> <script src="script.js"></script> </body> </html>
<head> contains metadata (info about the page, not visible content). The <body> contains everything the user actually sees on screen.
HTML Basics
Tags, Elements & Attributes
HTML is made of elements. An element consists of an opening tag, content, and a closing tag. Attributes provide extra information about an element.
<!-- Basic element anatomy --> <tagname attribute="value">Content</tagname> <!-- Example: an anchor (link) element --> <a href="https://example.com" target="_blank">Visit Site</a> <!-- Self-closing (void) elements have no content --> <img src="photo.jpg" alt="A description" /> <br /> <hr /> <input type="text" />
Headings & Paragraphs
Use heading tags h1–h6 to create hierarchy. There should only be one <h1> per page (the main title).
<h1>Page Title (largest)</h1> <h2>Section Heading</h2> <h3>Sub-section</h3> <h4>Sub-sub-section</h4> <h5>Minor heading</h5> <h6>Smallest heading</h6> <p>This is a paragraph. Use it for blocks of text.</p> <!-- Inline text formatting --> <p> Text can be <strong>bold</strong>, <em>italic</em>, <mark>highlighted</mark>, <s>strikethrough</s>, or <small>smaller</small>. </p>
Lists
<!-- Unordered (bullet) list --> <ul> <li>Apples</li> <li>Bananas</li> <li>Cherries</li> </ul> <!-- Ordered (numbered) list --> <ol> <li>Step one</li> <li>Step two</li> <li>Step three</li> </ol> <!-- Description list --> <dl> <dt>HTML</dt> <dd>HyperText Markup Language</dd> </dl>
Divs & Spans
<div> is a block-level container (takes full width, starts new line). <span> is an inline container (wraps inside text).
<!-- div: group block-level content --> <div class="card"> <h2>Card Title</h2> <p>Card content goes here.</p> </div> <!-- span: style inline text --> <p>The price is <span class="highlight">$9.99</span> today only.</p>
Semantic HTML5 Elements
Why Semantics Matter
Semantic elements describe their meaning to browsers and developers. They improve accessibility, SEO, and code readability. Use them instead of generic <div> wrappers wherever possible.
<body> <!-- Site-wide header with logo/nav --> <header> <nav> <a href="/">Home</a> <a href="/about">About</a> </nav> </header> <!-- Main content area --> <main> <!-- Self-contained piece of content --> <article> <header> <h1>Article Title</h1> <time datetime="2024-03-15">March 15, 2024</time> </header> <section> <p>Article content...</p> </section> <footer>Author: Jane Doe</footer> </article> <!-- Tangentially related content --> <aside> <p>Related links, ads, sidebars.</p> </aside> </main> <!-- Site-wide footer --> <footer> <p>© 2024 My Website</p> </footer> </body>
| Element | Purpose |
|---|---|
| <header> | Introductory content, logos, navigation |
| <nav> | Navigation links |
| <main> | Primary content (only once per page) |
| <article> | Self-contained content (blog post, card) |
| <section> | Thematic group of content |
| <aside> | Sidebar, related content |
| <footer> | Footer for a page or section |
| <figure> | Image with optional caption |
| <figcaption> | Caption for a <figure> |
| <time> | Dates and times |
| <details> | Collapsible disclosure widget |
| <summary> | Visible label for <details> |
Forms & Inputs
Building a Complete Form
<form action="/submit" method="POST"> <!-- Text input --> <label for="name">Full Name</label> <input type="text" id="name" name="name" placeholder="Jane Doe" required /> <!-- Email input (validates format automatically) --> <label for="email">Email Address</label> <input type="email" id="email" name="email" required /> <!-- Password input --> <input type="password" name="pass" minlength="8" required /> <!-- Number input --> <input type="number" name="age" min="1" max="120" /> <!-- Dropdown select --> <label for="role">Your Role</label> <select id="role" name="role"> <option value="">Select...</option> <option value="dev">Developer</option> <option value="design">Designer</option> </select> <!-- Multi-line text area --> <label for="msg">Message</label> <textarea id="msg" name="msg" rows="5" cols="40"></textarea> <!-- Checkboxes --> <input type="checkbox" id="agree" name="agree" /> <label for="agree">I agree to the terms</label> <!-- Radio buttons --> <input type="radio" name="size" value="sm" /> Small <input type="radio" name="size" value="lg" /> Large <!-- Submit button --> <button type="submit">Send Message</button> </form>
<label> to its input using matching for and id attributes. This improves accessibility and makes the label clickable to focus the input.
Media & Embeds
Images, Video & Audio
<!-- Image: always include alt text for accessibility --> <img src="photo.jpg" alt="A scenic mountain landscape" width="800" height="600" loading="lazy" /> <!-- Responsive image with sources for different sizes --> <picture> <source media="(min-width: 800px)" srcset="large.jpg" /> <source media="(min-width: 400px)" srcset="medium.jpg" /> <img src="small.jpg" alt="Responsive image" /> </picture> <!-- Video with fallback --> <video controls width="640" poster="thumbnail.jpg"> <source src="movie.mp4" type="video/mp4" /> <source src="movie.webm" type="video/webm" /> Your browser does not support video. </video> <!-- Audio --> <audio controls> <source src="audio.mp3" type="audio/mpeg" /> </audio> <!-- Embed a YouTube video --> <iframe width="560" height="315" src="https://www.youtube.com/embed/VIDEO_ID" title="Video title" allowfullscreen ></iframe>
Tables
Structured Data Tables
Tables are for displaying tabular data only — not for page layouts.
<table> <!-- Caption (accessible title for the table) --> <caption>Monthly Sales Report</caption> <!-- Table head --> <thead> <tr> <th scope="col">Month</th> <th scope="col">Revenue</th> <th scope="col">Sales</th> </tr> </thead> <!-- Table body --> <tbody> <tr> <td>January</td> <td>$12,400</td> <td>248</td> </tr> <tr> <td>February</td> <!-- colspan merges columns --> <td colspan="2">Data not available</td> </tr> </tbody> <!-- Table footer --> <tfoot> <tr> <td>Total</td> <td>$12,400</td> <td>248</td> </tr> </tfoot> </table>
Links & Navigation
Anchor Tags
<!-- External link (opens in new tab) --> <a href="https://example.com" target="_blank" rel="noopener noreferrer">External Site</a> <!-- Internal link --> <a href="/about.html">About Us</a> <!-- Link to section on the same page (anchor) --> <a href="#contact">Jump to Contact</a> <!-- Email link --> <a href="mailto:hello@example.com">Email Us</a> <!-- Phone link --> <a href="tel:+15551234567">Call Us</a> <!-- Download link --> <a href="/files/resume.pdf" download>Download PDF</a>
rel="noopener noreferrer" to external links that open in a new tab (target="_blank") — this prevents a security vulnerability called "tab-napping".
CSS Basics
How to Apply CSS
There are three ways to add CSS to your HTML:
<!-- 1. External stylesheet (RECOMMENDED) --> <link rel="stylesheet" href="styles.css" /> <!-- 2. Internal style block in the <head> --> <style> body { color: red; } </style> <!-- 3. Inline styles (avoid unless necessary) --> <p style="color: red; font-size: 18px;">Text</p>
CSS Rule Syntax
/* selector { property: value; } */ h1 { color: navy; font-size: 2rem; margin-bottom: 16px; } /* Class selector (reusable) */ .card { background: white; border-radius: 8px; padding: 24px; box-shadow: 0 2px 12px rgba(0,0,0,0.1); } /* ID selector (unique, one per page) */ #main-hero { background: linear-gradient(135deg, #667eea, #764ba2); height: 100vh; } /* Multiple selectors */ h1, h2, h3 { font-family: 'Georgia', serif; line-height: 1.2; }
The Box Model
Understanding the Box Model
Every HTML element is a rectangular box. The box model defines four layers from outside in:
.box { /* Content size */ width: 300px; height: 200px; /* Padding: space INSIDE the border */ padding: 20px; /* all sides */ padding: 10px 20px; /* top/bottom left/right */ padding: 5px 10px 15px 20px; /* top right bottom left */ padding-top: 8px; /* Border */ border: 2px solid #333; border-radius: 8px; /* Margin: space OUTSIDE the border */ margin: 0 auto; /* center horizontally */ margin-bottom: 24px; /* CRITICAL: include padding in width calculation */ box-sizing: border-box; } /* Apply border-box globally (RECOMMENDED) */ *, *::before, *::after { box-sizing: border-box; }
CSS Selectors
Essential Selectors
/* ── BASIC ── */ p { } /* element type */ .class-name { } /* class */ #id-name { } /* id */ * { } /* universal (all elements) */ /* ── COMBINATORS ── */ div p { } /* descendant (p inside div) */ div > p { } /* direct child only */ h2 + p { } /* immediately adjacent sibling */ h2 ~ p { } /* all following siblings */ /* ── PSEUDO-CLASSES (state) ── */ a:hover { } /* mouse over */ a:visited { } /* previously visited */ input:focus { } /* element is focused */ button:active{ } /* being clicked */ li:first-child { } /* first sibling */ li:last-child { } /* last sibling */ li:nth-child(2n){ } /* every even item */ li:nth-child(odd){ }/* every odd item */ p:not(.skip) { } /* not matching selector */ /* ── PSEUDO-ELEMENTS ── */ p::first-line { } /* first line of text */ p::first-letter{ } /* first letter (for drop caps) */ .quote::before { content: '"'; } .quote::after { content: '"'; } /* ── ATTRIBUTE SELECTORS ── */ input[type="text"] { } /* exact match */ a[href^="https"] { } /* starts with */ a[href$=".pdf"] { } /* ends with */ a[href*="google"] { } /* contains */
Typography
Font Properties
/* Import Google Fonts (in <head> or top of CSS) */ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap'); body { font-family: 'Inter', -apple-system, sans-serif; font-size: 16px; /* base size */ font-weight: 400; /* normal, bold=700 */ line-height: 1.6; /* unitless is best */ color: #1a1a1a; } h1 { font-size: 2.5rem; /* relative to root font size */ font-weight: 700; letter-spacing: -0.02em; /* tight for big headings */ text-transform: uppercase; } p { font-size: 1rem; text-align: left; /* or center, right, justify */ text-decoration: none; /* underline, line-through */ word-spacing: 0.05em; } /* Fluid typography: scales with viewport */ h1 { font-size: clamp(1.8rem, 5vw, 4rem); } /* Truncate text with ellipsis */ .truncate { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
Colors & Backgrounds
Color Formats
.element { /* Named color */ color: tomato; /* Hexadecimal (#RRGGBB or #RGB) */ color: #ff6347; color: #f63; /* shorthand */ /* RGB */ color: rgb(255, 99, 71); /* RGBA (with alpha/transparency 0–1) */ color: rgba(255, 99, 71, 0.8); /* HSL (Hue Saturation Lightness) */ color: hsl(9, 100%, 64%); /* Modern: oklch for perceptually uniform colors */ color: oklch(65% 0.2 30); } /* Backgrounds */ .hero { background-color: #1a1a2e; /* Linear gradient */ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); /* Radial gradient */ background: radial-gradient(circle at center, #ff9a9e, #fecfef); /* Background image */ background-image: url('hero.jpg'); background-size: cover; background-position: center; background-repeat: no-repeat; /* Multiple backgrounds (comma-separated) */ background: url('overlay.png') center/cover, linear-gradient(rgba(0,0,0,0.5), rgba(0,0,0,0.5)); }
Flexbox
One-Dimensional Layout
Flexbox arranges items in a single row or column. It's perfect for navbars, card rows, centering elements, and spacing items evenly.
.container { display: flex; /* Direction: row (default) | column | row-reverse | column-reverse */ flex-direction: row; /* Wrapping: nowrap (default) | wrap | wrap-reverse */ flex-wrap: wrap; /* Main axis (horizontal in row) */ justify-content: space-between; /* flex-start | flex-end | center | space-around | space-evenly */ /* Cross axis (vertical in row) */ align-items: center; /* flex-start | flex-end | stretch | baseline */ /* Spacing between items */ gap: 16px; } /* Perfect center (horizontal + vertical) */ .centered { display: flex; justify-content: center; align-items: center; height: 100vh; }
.item { /* Grow to fill remaining space */ flex-grow: 1; /* Shrink if needed */ flex-shrink: 0; /* 0 = never shrink */ /* Base size before growing/shrinking */ flex-basis: 200px; /* Shorthand: grow shrink basis */ flex: 1 0 200px; flex: 1; /* = 1 1 0 */ /* Override align-items for this specific item */ align-self: flex-end; /* Re-order (visual only, not DOM) */ order: 2; }
CSS Grid
Two-Dimensional Layout
Grid is for complex, two-dimensional layouts — rows AND columns simultaneously. It's the most powerful layout tool in CSS.
.grid { display: grid; /* Define 3 equal columns */ grid-template-columns: 1fr 1fr 1fr; /* Shorthand: */ grid-template-columns: repeat(3, 1fr); /* Responsive: auto-fill as many columns as fit */ grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); /* Define row heights */ grid-template-rows: auto 1fr auto; /* Gap between cells */ gap: 24px; column-gap: 20px; row-gap: 16px; } /* Named grid areas */ .layout { display: grid; grid-template-areas: "header header header" "sidebar main main" "footer footer footer"; grid-template-rows: 60px 1fr 50px; min-height: 100vh; } .header { grid-area: header; } .sidebar { grid-area: sidebar; } .main { grid-area: main; } .footer { grid-area: footer; } /* Spanning items across columns/rows */ .featured { grid-column: 1 / 3; /* spans 2 columns */ grid-row: 1 / span 2; /* spans 2 rows */ }
Positioning
The position Property
/* STATIC (default) - normal document flow */ .normal { position: static; } /* RELATIVE - offset from its natural position */ .relative { position: relative; top: 10px; left: 20px; /* Still occupies original space */ } /* ABSOLUTE - positioned relative to nearest positioned parent */ .parent { position: relative; } .child { position: absolute; top: 0; right: 0; /* Removed from normal flow */ } /* FIXED - stays on screen while scrolling */ .navbar { position: fixed; top: 0; left: 0; width: 100%; z-index: 1000; } /* STICKY - relative until it hits a threshold, then fixed */ .sticky-header { position: sticky; top: 0; z-index: 100; } /* z-index: controls stacking order (higher = on top) */ .modal { z-index: 1000; } .overlay { z-index: 999; }
Responsive Design
Media Queries
Media queries apply CSS rules only when conditions are met (like a certain screen width). Design mobile-first: write base styles for mobile, then expand for larger screens.
/* ── BASE STYLES (mobile, smallest screens) ── */ .container { width: 100%; padding: 0 16px; } .grid { display: grid; grid-template-columns: 1fr; /* 1 column on mobile */ } /* ── SMALL TABLETS (≥ 480px) ── */ @media (min-width: 480px) { .grid { grid-template-columns: repeat(2, 1fr); } } /* ── TABLETS (≥ 768px) ── */ @media (min-width: 768px) { .container { padding: 0 32px; } .grid { grid-template-columns: repeat(3, 1fr); } } /* ── DESKTOPS (≥ 1024px) ── */ @media (min-width: 1024px) { .container { max-width: 1200px; margin: 0 auto; } } /* ── LARGE SCREENS (≥ 1280px) ── */ @media (min-width: 1280px) { .grid { grid-template-columns: repeat(4, 1fr); } } /* ── DARK MODE ── */ @media (prefers-color-scheme: dark) { body { background: #0a0a0a; color: #f5f5f5; } } /* ── PRINT ── */ @media print { .no-print { display: none; } }
% (percentage of parent), vw/vh (percentage of viewport), rem (relative to root font size), em (relative to current element font size). Avoid fixed px widths for layout containers.
Transitions & Animations
CSS Transitions
Transitions smoothly animate a property from one value to another (on hover, focus, etc.)
.button { background: #3b82f6; color: white; padding: 10px 20px; border-radius: 6px; border: none; cursor: pointer; /* property duration timing-function delay */ transition: background 0.3s ease, transform 0.2s ease; } .button:hover { background: #2563eb; transform: translateY(-2px); } /* Transition all properties */ .card { transition: all 0.3s ease; } /* Common timing functions */ /* ease | linear | ease-in | ease-out | ease-in-out */ /* cubic-bezier(x1, y1, x2, y2) for custom curves */
CSS Keyframe Animations
/* 1. Define the animation */ @keyframes fadeIn { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } @keyframes pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.05); } } /* 2. Apply the animation */ .hero-text { /* name duration timing delay iteration direction */ animation: fadeIn 0.6s ease-out 0s 1 normal forwards; } .spinner { animation: spin 1s linear infinite; } .cta-button { animation: pulse 2s ease-in-out infinite; } /* Stagger children with animation-delay */ .card:nth-child(1) { animation-delay: 0s; } .card:nth-child(2) { animation-delay: 0.1s; } .card:nth-child(3) { animation-delay: 0.2s; } /* Respect reduced motion preferences */ @media (prefers-reduced-motion: reduce) { * { animation-duration: 0.01ms !important; } }
Transform Reference
.element { /* Move */ transform: translateX(50px); transform: translateY(-20px); transform: translate(50px, -20px); /* Rotate */ transform: rotate(45deg); /* Scale */ transform: scale(1.5); /* 150% size */ transform: scaleX(2); /* stretch horizontally */ /* Skew */ transform: skewX(15deg); /* Combine (read right to left) */ transform: translateY(-4px) scale(1.02) rotate(1deg); }
CSS Custom Properties (Variables)
Design Token System
CSS variables let you define values once and reuse them everywhere. Change a variable and the whole site updates — perfect for theming.
/* Define variables on :root (global scope) */ :root { /* Colors */ --color-primary: #3b82f6; --color-secondary: #8b5cf6; --color-text: #1a1a1a; --color-bg: #ffffff; /* Spacing scale */ --space-xs: 4px; --space-sm: 8px; --space-md: 16px; --space-lg: 32px; --space-xl: 64px; /* Typography */ --font-sans: 'Inter', sans-serif; --font-size-base: 16px; --font-size-lg: 1.125rem; /* Shadows */ --shadow-sm: 0 1px 3px rgba(0,0,0,0.1); --shadow-md: 0 4px 16px rgba(0,0,0,0.15); /* Border radius */ --radius: 8px; --radius-lg: 16px; --radius-full: 9999px; } /* Use variables with var() */ .card { background: var(--color-bg); padding: var(--space-lg); border-radius: var(--radius); box-shadow: var(--shadow-md); color: var(--color-text); } .button-primary { background: var(--color-primary); /* Fallback value if variable is undefined */ color: var(--button-text, white); } /* Dark mode by changing variables */ @media (prefers-color-scheme: dark) { :root { --color-text: #f5f5f5; --color-bg: #0a0a0a; } } /* Or via a class toggle with JavaScript */ [data-theme="dark"] { --color-text: #f5f5f5; --color-bg: #0a0a0a; }
Best Practices
HTML Best Practices
- Always declare
<!DOCTYPE html>and setlangon<html> - Use semantic elements instead of generic
<div>wrappers - Every
<img>must have analtattribute (even if empty for decorative images:alt="") - Use
<label>for every form input — never skip it - Keep only one
<h1>per page; maintain heading hierarchy - Add
loading="lazy"to images below the fold - Validate your HTML at
validator.w3.org
CSS Best Practices
- Apply
box-sizing: border-boxglobally at the top of your CSS - Use a CSS variable system for colors, spacing, and typography
- Write mobile-first styles, then expand with
min-widthmedia queries - Prefer
remfor font sizes andpxfor borders/shadows - Use
flexboxfor one-dimensional layouts,gridfor two-dimensional - Avoid deeply nested selectors — keep specificity low
- Use
@media (prefers-reduced-motion)to respect accessibility - Never use inline styles for layout — keep style in CSS files
- Organize CSS: custom properties → resets → base → components → utilities
Performance Tips
link rel="preconnect" before Google Fonts imports. Use display=swap to prevent invisible text during font loading. Use WebP images when possible — they're up to 30% smaller than JPEG with the same quality.
<head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Page Title — Site Name</title> <!-- SEO meta tags --> <meta name="description" content="Brief page description for search engines." /> <!-- Favicon --> <link rel="icon" href="/favicon.ico" /> <!-- Preconnect to speed up Google Fonts --> <link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <!-- Fonts with display=swap --> <link href="https://fonts.googleapis.com/css2?family=Inter&display=swap" rel="stylesheet" /> <!-- CSS last --> <link rel="stylesheet" href="styles.css" /> </head>